/*
 * CPU_Backend.cpp
 *
 *  Created on: 2010-06-13
 *      Author: Daniel
 */

#include "../inc/CPU_Backend.h"
#include <math.h>

int _cpu_init() {

	return 0;
}

int _cpu_shutdown() {

	return 0;
}

int _cpu_vector_copy(const Vector& source, Vector& dest) {
	if (source.getSize() <= 0 || dest.getSize() <= 0)
		return -1;
	if (source.getSize() != dest.getSize())
		return -1;

	for (int i = 0; i < source.getSize(); i++) {
		dest.set(i, source.get(i));
	}

	return 0;
}

int _cpu_vector_literal(Vector& dest, float begin, float end, float step) {

	if (dest.getSize() <= 0)
		return -1;

	if (step == 0) {
		return -1;
	}

	if (step > 0 && end <= begin)
		return -1;

	if (step < 0 && begin <= end)
		return -1;

	if (fabs(dest.getSize() - (1 + (end - begin) / step)) > 0.0001)
		return -1;

	for (int i = 0; i < dest.getSize(); i++) {
		dest.set(i, begin + i * step);
	}

	return 0;
}

int _cpu_vector_equal(const Vector& first, const Vector& second) {

	if (first.getSize() <= 0 || second.getSize() <= 0)
		return -1;
	if (first.getSize() != second.getSize())
		return -1;

	for (int i = 0; i < first.getSize(); i++) {
		if (first.get(i) != second.get(i))
			return 0;
	}

	return 1;
}

int _cpu_vector_nequal(const Vector& first, const Vector& second) {

	if (first.getSize() <= 0 || second.getSize() <= 0)
		return -1;
	if (first.getSize() != second.getSize())
		return -1;

	for (int i = 0; i < first.getSize(); i++) {
		if (first.get(i) != second.get(i))
			return 1;
	}

	return 0;
}

int _cpu_vector_plus_vector(Vector& result, const Vector& first,
		const Vector& second) {

	if (result.getSize() <= 0 || first.getSize() <= 0 || second.getSize() <= 0)
		return -1;
	if (result.getSize() != first.getSize() || result.getSize()
			!= second.getSize())
		return -1;

	for (int i = 0; i < result.getSize(); i++) {
		result.set(i, first.get(i) + second.get(i));
	}

	return 0;
}

int _cpu_vector_minus_vector(Vector& result, const Vector& first,
		const Vector& second) {

	if (result.getSize() <= 0 || first.getSize() <= 0 || second.getSize() <= 0)
		return -1;
	if (result.getSize() != first.getSize() || result.getSize()
			!= second.getSize())
		return -1;

	for (int i = 0; i < result.getSize(); i++) {
		result.set(i, first.get(i) - second.get(i));
	}

	return 0;
}

int _cpu_matrix_times_vector(Vector& result, const Matrix& matrix,
		const Vector& vector) {

	if (result.getSize() <= 0 || matrix.getRowsNumber() <= 0
			|| matrix.getColumnsNumber() <= 0 || vector.getSize() <= 0)
		return -1;
	if (matrix.getColumnsNumber() != vector.getSize() || matrix.getRowsNumber()
			!= result.getSize())
		return -1;

	for (int i = 0; i < matrix.getRowsNumber(); i++) {
		float val = 0;

		for (int j = 0; j < matrix.getColumnsNumber(); j++) {
			val += matrix.get(i, j) * vector.get(j);
		}
		result.set(i, val);
	}

	return 0;
}

int _cpu_vector_times_matrix(Vector& result, const Matrix& matrix,
		const Vector& vector) {

	if (result.getSize() <= 0 || matrix.getRowsNumber() <= 0
			|| matrix.getRowsNumber() <= 0 || vector.getSize() <= 0)
		return -1;
	if (matrix.getRowsNumber() != vector.getSize() || matrix.getColumnsNumber()
			!= result.getSize())
		return -1;

	for (int i = 0; i < matrix.getRowsNumber(); i++) {
		float val = 0;
		for (int j = 0; j < matrix.getColumnsNumber(); j++) {
			val += matrix.get(j, i) * vector.get(j);
		}
		result.set(i, val);
	}

	return 0;
}

int _cpu_matrix_copy(const Matrix& source, Matrix& dest) {

	if (source.getRowsNumber() <= 0 || source.getColumnsNumber() <= 0
			|| dest.getRowsNumber() <= 0 || dest.getColumnsNumber() <= 0)
		return -1;
	if (source.getRowsNumber() != dest.getRowsNumber()
			|| source.getColumnsNumber() != dest.getColumnsNumber())
		return -1;

	for (int i = 0; i < source.getRowsNumber(); i++) {
		for (int j = 0; j < source.getColumnsNumber(); j++) {
			dest.set(i, j, source.get(i, j));
		}
	}

	return 0;
}

int _cpu_matrix_equal(const Matrix& first, const Matrix& second) {

	if (first.getRowsNumber() <= 0 || first.getColumnsNumber() <= 0
			|| second.getRowsNumber() <= 0 || second.getColumnsNumber() <= 0)
		return -1;
	if (first.getRowsNumber() != second.getRowsNumber()
			|| first.getColumnsNumber() != second.getColumnsNumber())
		return -1;

	for (int i = 0; i < first.getRowsNumber(); i++) {
		for (int j = 0; j < first.getColumnsNumber(); j++) {
			if (first.get(i, j) != second.get(i, j))
				return 0;
		}
	}

	return 1;
}

int _cpu_matrix_nequal(const Matrix& first, const Matrix& second) {

	if (first.getRowsNumber() <= 0 || first.getColumnsNumber() <= 0
			|| second.getRowsNumber() <= 0 || second.getColumnsNumber() <= 0)
		return -1;
	if (first.getRowsNumber() != second.getRowsNumber()
			|| first.getColumnsNumber() != second.getColumnsNumber())
		return -1;

	for (int i = 0; i < first.getRowsNumber(); i++) {
		for (int j = 0; j < first.getColumnsNumber(); j++) {
			if (first.get(i, j) != second.get(i, j))
				return 1;
		}
	}

	return 0;
}

int _cpu_matrix_plus_matrix(Matrix& result, const Matrix& first,
		const Matrix& second) {

	if (result.getRowsNumber() <= 0 || result.getColumnsNumber() <= 0
			|| first.getRowsNumber() <= 0 || first.getColumnsNumber() <= 0
			|| second.getRowsNumber() <= 0 || second.getColumnsNumber() <= 0)
		return -1;
	if (result.getRowsNumber() != first.getRowsNumber()
			|| result.getColumnsNumber() != first.getColumnsNumber()
			|| result.getRowsNumber() != second.getRowsNumber()
			|| result.getColumnsNumber() != second.getColumnsNumber())
		return -1;

	for (int i = 0; i < result.getRowsNumber(); i++) {
		for (int j = 0; j < result.getColumnsNumber(); j++) {
			result.set(i, j, first.get(i, j) + second.get(i, j));
		}
	}

	return 0;
}

int _cpu_matrix_minus_matrix(Matrix& result, const Matrix& first,
		const Matrix& second) {

	if (result.getRowsNumber() <= 0 || result.getColumnsNumber() <= 0
			|| first.getRowsNumber() <= 0 || first.getColumnsNumber() <= 0
			|| second.getRowsNumber() <= 0 || second.getColumnsNumber() <= 0)
		return -1;
	if (result.getRowsNumber() != first.getRowsNumber()
			|| result.getColumnsNumber() != first.getColumnsNumber()
			|| result.getRowsNumber() != second.getRowsNumber()
			|| result.getColumnsNumber() != second.getColumnsNumber())
		return -1;

	for (int i = 0; i < result.getRowsNumber(); i++) {
		for (int j = 0; j < result.getColumnsNumber(); j++) {
			result.set(i, j, first.get(i, j) - second.get(i, j));
		}
	}

	return 0;
}

int _cpu_matrix_times_matrix(Matrix& result, const Matrix& first,
		const Matrix& second) {
	if (result.getRowsNumber() <= 0 || result.getColumnsNumber() <= 0
			|| first.getRowsNumber() <= 0 || first.getColumnsNumber() <= 0
			|| second.getRowsNumber() <= 0 || second.getColumnsNumber() <= 0)
		return -1;

	if (result.getRowsNumber() != first.getRowsNumber()
			|| result.getColumnsNumber() != second.getColumnsNumber()
			|| first.getColumnsNumber() != second.getRowsNumber())
		return -1;

	for (int i = 0; i < result.getRowsNumber(); i++) {
		for (int j = 0; j < result.getColumnsNumber(); j++) {
			float val = 0;
			for (int k = 0; k < first.getColumnsNumber(); k++) {
				val += first.get(i, k) * second.get(k, j);
			}
			result.set(i, j, val);
		}
	}

	return 0;
}

int _cpu_scalar_times_vector(Vector& result, const Vector& vector, float scalar) {

	if (result.getSize() <= 0 || vector.getSize() <= 0)
		return -1;
	if (result.getSize() != vector.getSize())
		return -1;

	for (int i = 0; i < result.getSize(); i++) {
		result.set(i, scalar * vector.get(i));
	}

	return 0;
}

int _cpu_scalar_times_matrix(Matrix& result, const Matrix& matrix, float scalar) {

	if (result.getRowsNumber() <= 0 || result.getColumnsNumber() <= 0
			|| matrix.getRowsNumber() <= 0 || matrix.getColumnsNumber() <= 0)
		return -1;
	if (result.getRowsNumber() != matrix.getRowsNumber()
			|| result.getColumnsNumber() != matrix.getColumnsNumber())
		return -1;

	for (int i = 0; i < result.getRowsNumber(); i++) {
		for (int j = 0; j < result.getColumnsNumber(); j++) {
			result.set(i, j, scalar * matrix.get(i, j));
		}
	}

	return 0;
}

int _cpu_vector_div_scalar(Vector& result, const Vector& vector, float scalar) {

	if (result.getSize() <= 0 || vector.getSize() <= 0)
		return -1;
	if (result.getSize() != vector.getSize())
		return -1;

	for (int i = 0; i < result.getSize(); i++) {
		result.set(i, vector.get(i) / scalar);
	}

	return 0;
}

int _cpu_matrix_div_scalar(Matrix& result, const Matrix& matrix, float scalar) {

	if (result.getRowsNumber() <= 0 || result.getColumnsNumber() <= 0
			|| matrix.getRowsNumber() <= 0 || matrix.getColumnsNumber() <= 0)
		return -1;
	if (result.getRowsNumber() != matrix.getRowsNumber()
			|| result.getColumnsNumber() != matrix.getColumnsNumber())
		return -1;

	for (int i = 0; i < result.getRowsNumber(); i++) {
		for (int j = 0; j < result.getColumnsNumber(); j++) {
			result.set(i, j, matrix.get(i, j) / scalar);
		}
	}

	return 0;
}
